/* 遵守斗鱼SST协议的WS客户端 */

import EventEmitter from 'events'
import WebSocket from 'ws'
import { abConcat, ab2string, string2ab } from './helper'
import { serialize, unserialize } from './protocol_stt'
import config from '../Config'

export default class Client extends EventEmitter {
  _littleEndian = true
  _packLen = 0

  static serialize = serialize
  static unserialize = unserialize

  constructor (ip, port) {
    super()
    this.ip = ip
    this.port = port
  }

  get isConnected () {
    return this._socket && this._socket.readyState === WebSocket.OPEN
  }

  connect () {
    if (this.isConnected) return
    this._socket = new WebSocket(`wss://${this.ip}:${this.port}`, { headers: { Origin: 'https://www.douyu.com' } })
    this._socket._binaryType = 'arraybuffer'
    this._socket.onclose = this._onClose.bind(this)
    this._socket.onerror = this._onError.bind(this)
    this._socket.onmessage = this._onData.bind(this)
    this._socket.onopen = this._onOpen.bind(this)
    if (config._App.Debug) console.debug('try connect', this.port, this.ip)
  }

  close () {
    this._socket.onclose = null
    this._socket.onerror = null
    this._socket.onmessage = null
    this._socket.onopen = null
    let socket = this._socket
    this._socket = null
    if (socket.readyState === WebSocket.OPEN) socket.close()
    this._onClose()
  }

  sendMsg (data) {
    if (config._App.Debug) console.debug('sent msg', `[${data.type}]`, data, serialize(data))
    if (typeof data !== 'string') data = serialize(data)
    data = abConcat(string2ab(data), [0])
    let msgLength = 8 + data.byteLength
    let dataView = new DataView(new ArrayBuffer(msgLength + 4))
    let offset = 0
    dataView.setUint32(offset, msgLength, this._littleEndian)
    offset += 4
    dataView.setUint32(offset, msgLength, this._littleEndian)
    offset += 4
    dataView.setInt16(offset, 689, this._littleEndian)
    offset += 2
    dataView.setInt8(offset, 0)
    offset += 1
    dataView.setInt8(offset, 0)
    offset += 1
    new Uint8Array(dataView.buffer).set(data, offset)
    this._socket.send(dataView.buffer)
  }

  _onClose () {
    if (this._socket) {
      // 非预料中的关闭, 重连并触发主动close来emit事件
      this.close()
      this.connect()
      return
    }
    this.emit('close')
  }

  _onError (err) {
    console.error('_onError', err)
    // 非预期的错误, 主动关闭并重连
    this.close()
    this.connect()
  }

  _onData ({ data }) {
    this._buffer ? this._buffer = abConcat(this._buffer, data).buffer : this._buffer = data
    this._parseMsg()
  }

  _onOpen () {}

  _parseMsg () {
    while (this._buffer && this._buffer.byteLength > 0) {
      let bufferView = new DataView(this._buffer)
      if (this._packLen === 0) {
        if (this._buffer.byteLength < 4) return
        this._packLen = bufferView.getUint32(0, this._littleEndian)
        this._buffer = this._buffer.slice(4)
      }
      if (this._buffer.byteLength < this._packLen) return

      let raw = ab2string(this._buffer.slice(8, this._packLen - 1))
      this._buffer = this._buffer.slice(this._packLen)
      this._packLen = 0
      let msg = unserialize(raw).too()
      this._onMessage(msg)
    }
  }

  _onMessage (msg) {}
}
